

#include "unity.h"
#include "unity_fixture.h"

#include "Debug.h"
#include "BSP_Sleep.h"

#include <Reader/Reader.h>

#define AEND  "\x1b[0m"
#define _RED_(s) RTT_CTRL_TEXT_BRIGHT_RED s AEND
#define _GREEN_(s) RTT_CTRL_TEXT_BRIGHT_GREEN s AEND
#define _YELLOW_(s) RTT_CTRL_TEXT_BRIGHT_YELLOW s AEND
#define _CYAN_(s) RTT_CTRL_TEXT_BRIGHT_CYAN s AEND

TEST_GROUP(MifarePlus);


TEST_SETUP(MifarePlus)
{
	reader.hfFlags = TAG_MASK_MIFARE;
	Reader_NFC_LoadProfile(reader.hfFlags, 0, 0, 0);
}

TEST_TEAR_DOWN(MifarePlus)
{
	Reader_NFC_RfOff();
}

static int CheckCardPresent(int num){
	int ret = -1;
	int i, searchNum = num;
	SimpleTag_T simpleTag;
	
	for(i = 0; i < searchNum; i++){
		Reader_NFC_RfOff();
		BSP_Sleep_Ms(500);
		ret = Reader_NFC_Discovery2(&simpleTag, 0);
		if(!ret){
			LOG_B("\n--> UID: ", simpleTag.uid, simpleTag.ulen, 8);
			break;
		}
	}

	return ret;
}

/*
* \verbatim
* +-------------+-------------+-------------+-------------+-------------+
* | bFirstAuth	|	 AUTHENTICATE_NON_FIRST |	  AUTHENTICATE_FIRST	|
* +-------------+-------------+-------------+-------------+-------------+
* | bLayer4Comm | ISO14443_L3 | ISO14443_L4 | ISO14443_L3 | ISO14443_L4 |
* +-------------+-------------+-------------+-------------+-------------+
* | wBlockNr	|		X	  | 	  X 	|		X	  | 	  X 	|
* | wKeyNumber	|		X	  | 	  X 	|		X	  | 	  X 	|
* | wKeyVersion |		X	  | 	  X 	|		X	  | 	  X 	|
* | bLenPcdCap2 |		-	  | 	  - 	|		-	  | 	  X 	|
* | pPcdCap2In	|		-	  | 	  - 	|		-	  | 	  X 	|
* | pPcdCap2	|		-	  | 	  - 	|		-	  | 	  X 	|
* | pPdCap2 	|		-	  | 	  - 	|		-	  | 	  X 	|
* +-------------+-------------+-------------+-------------+-------------+
*/

static int mfp_write_perso(uint16_t block_addr, uint8_t num_block, uint8_t* block_data){
	void * pDataParams = phNfcLib_GetDataParams(PH_COMP_AL_MFPEVX);
	return phalMfpEVx_WritePerso(pDataParams, 1, block_addr, num_block, block_data);
}

static int mfp_commit_perso(uint8_t option){
	void * pDataParams = phNfcLib_GetDataParams(PH_COMP_AL_MFPEVX);
	return  phalMfpEVx_CommitPerso(
        pDataParams,                                                 /**< [In] Pointer to this layer's parameter structure. */
        option,                                                    /**< [In] Option to be used for Security Level switching.
                                                                             *          \arg #PHAL_MFPEVX_MAINTIAN_BACKWARD_COMPATIBILITY
                                                                             *          \arg #PHAL_MFPEVX_SWITCH_SECURITY_LEVEL_1
                                                                             *          \arg #PHAL_MFPEVX_SWITCH_SECURITY_LEVEL_3
                                                                             */
        PHAL_MFPEVX_ISO14443_L4                                                 /**< [In] ISO14443 protocol to be used.
                                                                             *          \arg #PHAL_MFPEVX_ISO14443_L3
                                                                             *          \arg #PHAL_MFPEVX_ISO14443_L4
                                                                             */
    );
}

static int mfp_auth_sl1(uint16_t key_addr, uint8_t* keys){
	uint8_t ver = 0;
	uint8_t keyNo = 1;
	void* key_store = phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	phKeyStore_FormatKeyEntry(key_store, 1, PH_KEYSTORE_KEY_TYPE_AES128);
	phKeyStore_SetKeyAtPos(key_store, keyNo, 0,
							PH_KEYSTORE_KEY_TYPE_AES128, keys, ver);
	void * pDataParams = phNfcLib_GetDataParams(PH_COMP_AL_MFPEVX);
	uint8_t bLenPcdCap2 = 6;
	uint8_t PcdCap2In[6] = {0};
	uint8_t PdCap2[6];
	uint8_t PcdCap2Out[6];
	phStatus_t status = phalMfpEVx_AuthenticateSL1(pDataParams, 1, 1, key_addr, keyNo,
    		ver, 0, NULL, bLenPcdCap2, PcdCap2In, PcdCap2Out, PdCap2);
	return status;
}

static int mfp_active(void){
	phacDiscLoop_Sw_DataParams_t * pDataParams = reader.pDiscLoop;
	uint8_t      PH_MEMLOC_REM bCidEnabled;
    uint8_t      PH_MEMLOC_REM bCid;
    uint8_t      PH_MEMLOC_REM bNadSupported;
    uint8_t      PH_MEMLOC_REM bFwi;
    uint8_t      PH_MEMLOC_REM bFsdi;
    uint8_t      PH_MEMLOC_REM bFsci;
	phStatus_t status;
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_SET_EMD, PH_ON));

	PH_CHECK_SUCCESS_FCT(status, phpalI14443p4a_ActivateCard(
		pDataParams->pPal1443p4aDataParams,
		pDataParams->sTypeATargetInfo.sTypeA_I3P4.bFsdi,
		pDataParams->sTypeATargetInfo.sTypeA_I3P4.bCid,
		pDataParams->sTypeATargetInfo.sTypeA_I3P4.bDri,
		pDataParams->sTypeATargetInfo.sTypeA_I3P4.bDsi,
		pDataParams->sTypeATargetInfo.sTypeA_I3P4.pAts));

	/* Retrieve 14443-4A protocol parameter */
	PH_CHECK_SUCCESS_FCT(status, phpalI14443p4a_GetProtocolParams(
		pDataParams->pPal1443p4aDataParams,
		&bCidEnabled,
		&bCid,
		&bNadSupported,
		&bFwi,
		&bFsdi,
		&bFsci));


	/* Set 14443-4 protocol parameter */
	PH_CHECK_SUCCESS_FCT(status, phpalI14443p4_SetProtocol(
		pDataParams->pPal14443p4DataParams,
		bCidEnabled,
		bCid,
		bNadSupported,
		pDataParams->sTypeATargetInfo.sTypeA_I3P4.bNad,
		bFwi,
		bFsdi,
		bFsci));

	return status;
}

IGNORE_TEST(MifarePlus, SL0)
{
	//个人化：CardMasterKey，CardConfigurationKey，L3SwitchKey全部设置为0xFF，切换到SL1安全级别。
	int ret = CheckCardPresent(10);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("card not present!"));
	uint8_t block_data[16];
	memset(block_data, 0xFF, sizeof(block_data));
	ret = mfp_write_perso(0x9000, 1, block_data);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("phalMfpEVx_Int_WritePerso write CardMasterKey fail!") );
	ret = mfp_write_perso(0x9001, 1, block_data);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("phalMfpEVx_Int_WritePerso write CardConfigurationKey fail!") );
	ret = mfp_write_perso(0x9003, 1, block_data);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("phalMfpEVx_Int_WritePerso write L3SwitchKey fail!") );
	ret = mfp_write_perso(0x9004, 1, block_data);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("phalMfpEVx_Int_WritePerso write SL1CardAuthKey fail!") );
	ret = mfp_write_perso(0x9006, 1, block_data);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("phalMfpEVx_Int_WritePerso write L3SectorSwitchKey fail!") );
	ret = mfp_write_perso(0x9007, 1, block_data);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("phalMfpEVx_Int_WritePerso write L1L3MixSectorSwitchKey fail!") );
	ret = mfp_commit_perso(PHAL_MFPEVX_SWITCH_SECURITY_LEVEL_1);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("commit perso fail!"));
}

TEST(MifarePlus, SL1)
{
	int ret = CheckCardPresent(10);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("card not present!"));
	ret = mfp_active();
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("card active fail!"));
	uint16_t addr = 0x9000;
	uint8_t key[16];
	memset(key, 0xFF, sizeof(key));
	ret = mfp_auth_sl1(addr, key);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("mfp_auth_sl1 fail!") );
	addr = 0x9000;
	ret = mfp_auth_sl1(addr, key);
	TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, _RED_("mfp_auth_sl1 fail!") );
}


IGNORE_TEST(MifarePlus, SL3)
{


}




